<script setup>
import { useResizeObserver } from '@vueuse/core'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import TWEEN from '@tweenjs/tween.js'
import { getElementSize } from '@/views/study/three/composables/index.js'

const webgl = ref(null)

let renderer = null
let camera = null
let orbit = null
let mesh = null

onMounted(() => {
  const { width, height } = getElementSize(webgl)

  const scene = new THREE.Scene()
  camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 1000)

  camera.position.set(100, 100, 100)
  camera.lookAt(0, 0, 0)

  const lights = []
  lights[0] = new THREE.DirectionalLight('#FFF', 5)
  lights[1] = new THREE.DirectionalLight('#FFF', 5)
  lights[2] = new THREE.DirectionalLight('#FFF', 5)

  lights[0].position.set(0, 200, 0)
  lights[1].position.set(100, 200, 100)
  lights[2].position.set(-100, -200, -100)

  scene.add(...lights)

  const geometry = new THREE.SphereGeometry(5, 25, 25)
  const material = new THREE.MeshPhongMaterial({
    color: '#156289',
  })

  mesh = new THREE.Mesh(geometry, material)

  scene.add(mesh)

  const axesHelper = new THREE.AxesHelper(25)
  scene.add(axesHelper)

  renderer = new THREE.WebGLRenderer()
  renderer.setSize(width, height)
  renderer.render(scene, camera)
  webgl.value.appendChild(renderer.domElement)

  orbit = new OrbitControls(camera, renderer.domElement)
  orbit.enableDamping = true

  handleAddEventListener()

  function render() {
    requestAnimationFrame(render)

    TWEEN.update()

    renderer.render(scene, camera)
  }

  render()
})

function createCameraTween(endPos, endTarget) {
  new TWEEN.Tween({
    x: camera.position.x,
    y: camera.position.y,
    z: camera.position.z,
    tx: orbit.target.x,
    ty: orbit.target.y,
    tz: orbit.target.z,
  })
    .easing(TWEEN.Easing.Quadratic.InOut)
    .to({
      x: endPos.x,
      y: endPos.y,
      z: endPos.z,
      tx: endTarget.x,
      ty: endTarget.y,
      tz: endTarget.z,
    }, 1000)
    .onUpdate((obj) => {
      camera.position.set(obj.x, obj.y, obj.z)
      orbit.target.set(obj.tx, obj.ty, obj.tz)
      orbit.update()
    })
    .start()
}

function handleHome() {
  createCameraTween(new THREE.Vector3(100, 100, 100), new THREE.Vector3(0, 0, 0))
}

function handleBall(mesh) {
  const pos = new THREE.Vector3()
  mesh.getWorldPosition(pos)

  const pos2 = pos.clone().addScalar(30)

  pos2.setZ(-15)

  createCameraTween(pos2, new THREE.Vector3(0, 0, 0))
}

function handleAddEventListener() {
  const raster = new THREE.Raycaster()

  renderer.domElement.addEventListener('click', (e) => {
    const { width, height } = getElementSize(webgl)
    const { offsetX, offsetY } = e

    const x = (offsetX / width) * 2 - 1
    const y = -(offsetY / height) * 2 + 1

    raster.setFromCamera(new THREE.Vector2(x, y), camera)

    const intersects = raster.intersectObjects([mesh])
    if (intersects.length)
      handleBall(intersects[0].object)
  })
}

function resizeHandler() {
  const { width, height } = getElementSize(webgl)

  camera.aspect = width / height
  camera.updateProjectionMatrix()

  renderer.setSize(width, height)
}

useResizeObserver(webgl, () => {
  resizeHandler()
})
</script>

<template>
  <div flex="~ col" gap="5px">
    <n-card size="small">
      <n-flex>
        <n-button size="small" @click="handleHome">
          首页
        </n-button>
      </n-flex>
    </n-card>

    <div ref="webgl" flex="1" overflow="hidden" />
  </div>
</template>
